﻿/// @file fmMain.cs The main form for this application

using System;
using System.Reflection;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Acrobat;
using System.Threading;
using System.Drawing.Printing;

namespace BatchPrintingWithAcrobatSDK
{
    /// Main form
    public partial class fmMain : Form
    {
        delegate void dStoppedBatchProcess(bool result);
        delegate void dPrintInfo(string msg);
        delegate CheckedListBox.CheckedIndexCollection dGetCheckedIndices();
        delegate string dGetItemPath(int n);
        delegate void dSetItemChecked(int n, bool state);
        delegate string dGetPrinterName();
        delegate string dGetBitmapDPI();
        delegate int dGetColorOverride();
        Thread tBatchPrinting = null;

        public fmMain()
        {
            InitializeComponent();
            Properties.Settings.Default.Reload();
        }

        private void fmMain_Load(object sender, EventArgs e)
        {
            btStop.Enabled = false;
            UpdatePrinterNames();
        }

        private void UpdatePrinterNames()
        {
            lsPrinterName.Items.Clear();
            foreach (string printer in PrinterSettings.InstalledPrinters)
                lsPrinterName.Items.Add(printer);

            string name = Properties.Settings.Default.PrinterName;
            if (name.Length == 0)
            {
                // Choose the default printer
                var doc = new PrintDocument();
                lsPrinterName.Text = doc.PrinterSettings.PrinterName;
                doc.Dispose();
            }
            else
            {
                // Choose by the default settings
                lsPrinterName.Text = name;
            }
        }

        private void PrintInfo(string msg)
        {
            if(this.InvokeRequired)
            {
                Invoke(new dPrintInfo(PrintInfo), new object[] {msg});
                return;
            }
            txInfo.Text += msg + Environment.NewLine;
            txInfo.SelectionStart = txInfo.TextLength - 1;
            txInfo.SelectionLength = 0;
            txInfo.ScrollToCaret();
        }

        private void StoppedBatchProcess(bool result)
        {
            if (this.InvokeRequired)
            {
                Invoke(new dStoppedBatchProcess(StoppedBatchProcess), new object[] { result });
                return;
            }
            btStop.Enabled = false;
            btStart.Enabled = true;
        }

        private CheckedListBox.CheckedIndexCollection GetCheckedIndices()
        {
            if (this.InvokeRequired)
                return (CheckedListBox.CheckedIndexCollection)Invoke(new dGetCheckedIndices(GetCheckedIndices), null);
            return lsFiles.CheckedIndices;
        }

        private string GetItemPath(int n)
        {
            if (this.InvokeRequired)
                return (string)Invoke(new dGetItemPath(GetItemPath), new object[] { n });
            return lsFiles.Items[n].ToString();
        }

        private void SetItemChecked(int n, bool state)
        {
            if (this.InvokeRequired)
            {
                Invoke(new dSetItemChecked(SetItemChecked), new object[] { n, state });
                return;
            }
            lsFiles.SetItemChecked(n, state);
        }

        private string GetPrinterName()
        {
            if (this.InvokeRequired)
                return (string)Invoke(new dGetPrinterName(GetPrinterName), null);
            return lsPrinterName.Text;
        }

        private string GetBitmapDPI()
        {
            if (this.InvokeRequired)
                return (string)Invoke(new dGetBitmapDPI(GetBitmapDPI), null);
            return nuBitmapDPI.Value.ToString(); 
        }

        private int GetColorOverride()
        {
            if (this.InvokeRequired)
                return (int)Invoke(new dGetColorOverride(GetColorOverride), null);
            return lsColorOverride.SelectedIndex;
        }

        // Batch printing on another thread
        private void BatchPrinting()
        {
            string path = "No File";

            try
            {
                // Batch printing for checked items
                var acro = new AcroAppClass();
                var avdoc = new AcroAVDocClass();
                foreach (int n in GetCheckedIndices())
                {
                    // Get pathname from the list
                    path = GetItemPath(n);
                    PrintInfo("Processing " + path);

                    // Open a pdf document
                    if (avdoc.Open(path, ""))
                    {
                        // Get pdf informations
                        var pddoc = (CAcroPDDoc)avdoc.GetPDDoc();
                        int pages = pddoc.GetNumPages();
                        string name = pddoc.GetFileName();

                        // Invoke Acrobat JavaScript
                        Object js = pddoc.GetJSObject();
                        Type t = js.GetType();
                        var callMethod = BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance;
                        var setProperty = BindingFlags.SetProperty;
                        //var getProperty = BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance;

                        // Get a PrintParams object
                        Object pp = t.InvokeMember("getPrintParams", callMethod, null, js, null);

                        // Set printerName property
                        t.InvokeMember("printerName", setProperty, null, pp, new object[] { GetPrinterName() });

                        // Set bitmapDPI property
                        t.InvokeMember("bitmapDPI", setProperty, null, pp, new object[] { GetBitmapDPI() });

                        // Set colorOverride property
                        t.InvokeMember("colorOverride", setProperty, null, pp, new object[] { GetColorOverride() });

                        // Print
                        object[] param2 = { false, 0, pages - 1, true, true, true };
                        bool res = (bool)t.InvokeMember("print", callMethod, null, js, param2);
                        if (res == false)
                            throw new Exception("Failed to invoke print method");

                        avdoc.Close(1);

                        // Uncheck succeeded item
                        SetItemChecked(n, false);
                        PrintInfo("Succeeded to print " + path);
                    }
                    else
                    {
                        throw new Exception("Failed to open");
                    }
                }
            }
            catch (Exception ex)
            {
                try
                {
                    PrintInfo("ERROR:" + path + ":" + ex.Message);
                    StoppedBatchProcess(false);
                }
                catch (Exception)
                {
                    // Pass all exceptions
                }
                return;
            }
            StoppedBatchProcess(true);
            PrintInfo("Succeeded for all files.");
        }

        /// "Start" button clicked
        private void btStart_Click(object sender, EventArgs e)
        {
            btStart.Enabled = false;
            btStop.Enabled = true;
            tBatchPrinting = new Thread(new ThreadStart(BatchPrinting));
            tBatchPrinting.Start();
        }

        private void StopBatchPrinting()
        {
            if (tBatchPrinting != null)
            {
                PrintInfo("PLEASE KILL Acrobat.exe PROCESS TO STOP...");
                tBatchPrinting.Abort();
                tBatchPrinting = null;
            }
        }

        /// "Stop" button clicked
        private void btStop_Click(object sender, EventArgs e)
        {
            StopBatchPrinting();
        }

        /// Draged into the listbox
        private void lsFiles_DragEnter(object sender, DragEventArgs e)
        {
            // Accept file drop format
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.Copy;
            else
                e.Effect = DragDropEffects.None;
        }

        /// Droped on the listbox
        private void lsFiles_DragDrop(object sender, DragEventArgs e)
        {
            var pathList = (string[])e.Data.GetData(DataFormats.FileDrop, false);
            foreach (string path in pathList)
            {
                lsFiles.Items.Add(path, true);
            }
        }

        private void btClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void fmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            StopBatchPrinting();
        }

        private void fmMain_FormClosed(object sender, FormClosedEventArgs e)
        {
            Properties.Settings.Default.Save();
        }
    }
}
